/************************************************************************
 * AIDE/Tools - Automata Identification Engine
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     
 * Description  :     
 * Change log   :     	-Date:  Change
 ************************************************************************/
using System;
using SMLib;
using SMLib.Automata.MM;
using SMLib.Automata.IA;

namespace SUT
{
	class MainClass
	{
		#region -=[ Parameters ]=-
		class Options
		{
			public Options ()
			{
				No_Params = true;
				Help = false;
				ModelType = "";
				Ver = false;
				Port_Specified = false;
				Port = -1;
				Model = "";
				lib = "";
				cls = "";
			}

			public bool No_Params;
			public bool Help;
			public string ModelType;
			public bool Ver;
			public bool Port_Specified;
			public int Port;
			public string Model;
			public string lib;
			public string cls;
		}

		private static Options ParseParams (string[] args)
		{
			Options opt = new Options ();
			if (args.Length == 0) {
				opt.No_Params = true;
			} else {
				opt.No_Params = false;
				for (int i=0; i<args.Length; i++) {
					switch (args [i]) {
					case "-help":
						opt.Help = true;
						break;
					case "-port":
						if (i >= args.Length)
							throw new Exception ("Exception: After -p parameter, the port is expected");
						i++;
						string portSt = args [i];
						int port;
						//* here we better use try catch
						port = Int32.Parse (portSt); 
						opt.Port = port;
						opt.Port_Specified = true;
						break;
					case "-m":
						if (i >= args.Length)
							throw new Exception ("Exception: After -m parameter, the model is expected");
						i++;
						opt.Model = args [i];							
						break;
					case "-v":
						opt.Ver = true;
						break;
					case "-l":
						if (i >= args.Length)
							throw new Exception ("Exception: After -l parameter, the library is expected");
						i++;
						opt.lib = args [i];							
						break;
					case "-c":
						if (i >= args.Length)
							throw new Exception ("Exception: After -c parameter, the class is expected");
						i++;
						opt.cls = args [i];							
						break;
					case "-t":
						if (i >= args.Length)
							throw new Exception ("Exception: After -t parameter, the type of model is expected");
						i++;
						if (args [i] == "MM")
							opt.ModelType = "MM";
						else if (args [i] == "IA")
							opt.ModelType = "IA";
						else
							throw new Exception ("Exception: Unknown model type");
						
						break;
					}					
				}				
			}
			return opt;
		}
		#endregion
		/// <summary>
		/// Prints the help message
		/// </summary>
		static void PrintHelp ()
		{
			Console.WriteLine ("usage: SUT [-help] [-v] [--port PORT]  modelfile");
			Console.WriteLine (" -help: shows this message.");
			Console.WriteLine (" -v: use debugging mode and so, writes the input and output.");
			Console.WriteLine (" -port Port: list to the specified port (1000 is the default).");
			Console.WriteLine (" -t TYPE (type of model [MM/IA])");
			Console.WriteLine (" For input model, there are 2 options. 1-Dot file with:");
			Console.WriteLine ("    -m MODEL: the input dot model");
			Console.WriteLine (" Or a library file:");
			Console.WriteLine ("    -l LIBRARY: the input library");
			Console.WriteLine ("    -c CLASS: the class to be instanciated");
		}

		/// <summary>
		/// The entry point of the program, where the program control starts and ends.
		/// </summary>
		/// <param name="args">The command-line arguments.</param>
		public static void Main (string[] args)
		{
			Options opt = ParseParams (args);
			if (opt.No_Params) {
				Console.WriteLine ("usage: SUT [-help] [-v] [-port PORT] -t TYPE -m MODEL -l LIBRRY -c CLASS");
				return;
			}
			if (opt.Help) {
				PrintHelp ();
				return;
			}
			int port = (opt.Port_Specified ? opt.Port : 1000);
			if (opt.lib == "" && opt.Model == "") {
				Console.WriteLine ("You should give an input!");
				return;
			}
			if (opt.lib != "" && opt.Model != "") {
				Console.WriteLine ("Lib:" + opt.lib + " Model:" + opt.Model);
				Console.WriteLine ("You should give just one input!");
				return;
			}

			if (opt.ModelType == "MM") {
				//* Mealy machine
				IBlackBox_MM bbm = null;
				if (opt.Model != "") {
					MealyMachine m = SMLib.Interoperability.DOT.DotHelper_MM.ReadFromDot (opt.Model);
					bbm = new SUL_Emulator_MM (m);
				} else if (opt.lib != "" && opt.cls != "") {
					LoadSUL loader = new LoadSUL (opt.lib);
					bbm = loader.LoadMealy (opt.cls);
				} else {
					Console.WriteLine ("The class is not defined!");
					return;
				}

				Console.WriteLine ("SUL simulation socketserver\n" +
					" -> listening at port : " + port + "\n" +
					" -> verbose mode : " + opt.Ver + "\n" +
					" -> the server has a timeout of 120 seconds" +
					"    note: to prevent unnecessary servers to keep on running");

				SUL_MM_WrapperTcp wrapper = new SUL_MM_WrapperTcp (port, bbm);
				wrapper.Start ();

			} else if (opt.ModelType == "IA") {
				//* Interface automata
				IBlackBox_IA bbm = null;
				if (opt.Model != "") {
					InterfaceAutomaton m = SMLib.Interoperability.DOT.DotHelper_IA.ReadFromDot (opt.Model);
					bbm = new SUL_Emulator_IA (m);
				}  else if (opt.lib != "" && opt.cls != "") {
					LoadSUL loader = new LoadSUL (opt.lib);
					bbm = loader.LoadIA(opt.cls);
				} else {
					Console.WriteLine ("The class is not defined!");
					return;
				}

				Console.WriteLine ("SUL simulation socketserver\n" +
				                   " -> listening at port : " + port + "\n" +
				                   " -> verbose mode : " + opt.Ver + "\n" +
				                   " -> the server has a timeout of 120 seconds" +
				                   "\n\tnote: to prevent unnecessary servers to keep on running");

				SUL_IA_WrapperTcp wrapper = new SUL_IA_WrapperTcp (port, bbm);
				wrapper.Start ();
			}
			//Console.WriteLine("Finished! Press any key to exit...");
			//Console.ReadKey();
		}
	}
}
